package com.abp.service.impl;

import com.abp.entity.Book;
import com.abp.entity.BookRanking;
import com.abp.entity.UserBookRating;
import com.abp.mapper.BookMapper;
import com.abp.mapper.UserBookRatingMapper;
import com.abp.service.RankingService;
import com.abp.utils.UserRatingVector;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.commons.math3.ml.clustering.KMeansPlusPlusClusterer;
import org.apache.commons.math3.ml.clustering.Cluster;
import org.apache.commons.math3.ml.clustering.CentroidCluster;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class RankingServiceImpl implements RankingService {

    @Autowired
    private UserBookRatingMapper userBookRatingMapper;
    @Autowired
    private BookMapper bookMapper;

    @Override
    public List<BookRanking> getBookRankingByUserId(int userId) {
        // 1. 获取所有用户对图书的评分数据
        List<UserBookRating> ratings = userBookRatingMapper.selectList(null);

        // 2. 按用户ID分组评分数据
        Map<Integer, Map<Integer, Float>> userRatings = ratings.stream()
                .collect(Collectors.groupingBy(
                        UserBookRating::getUserId,
                        Collectors.toMap(UserBookRating::getBookId, UserBookRating::getRating)
                ));

        // 3. 转换成 KMeans 需要的数据格式：每个用户的评分向量
        List<UserRatingVector> userRatingVectors = new ArrayList<>();
        for (Map<Integer, Float> rating : userRatings.values()) {
            double[] vector = new double[bookMapper.selectList(null).size()];
            for (Map.Entry<Integer, Float> entry : rating.entrySet()) {
                vector[entry.getKey() - 1] = entry.getValue();  // 评分对应图书的索引
            }
            userRatingVectors.add(new UserRatingVector(vector));
        }

        // 4. 使用 KMeans 算法进行聚类（假设分成 3 类）
        KMeansPlusPlusClusterer<UserRatingVector> kMeans = new KMeansPlusPlusClusterer<>(5);
        List<CentroidCluster<UserRatingVector>> clusters = kMeans.cluster(userRatingVectors);

        // 5. 找出用户所在的聚类
        int userIndex = new ArrayList<>(userRatings.keySet()).indexOf(userId);
        List<BookRanking> bookRankings = new ArrayList<>();
        for (Cluster<UserRatingVector> cluster : clusters) {
            if (cluster.getPoints().contains(userRatingVectors.get(userIndex))) {
                // 6. 获取用户所在聚类的图书排名
                bookRankings = getRankingForCluster(cluster, userRatings);
                break;
            }
        }

        return bookRankings;
    }

    // 根据聚类中的评分信息，生成图书的喜好排名
    private List<BookRanking> getRankingForCluster(Cluster<UserRatingVector> cluster, Map<Integer, Map<Integer, Float>> userRatings) {
        Map<Integer, Double> bookAverageRatings = new HashMap<>();

        // 计算聚类中所有用户对图书的平均评分
        for (UserRatingVector vector : cluster.getPoints()) {
            double[] ratings = vector.getPoint();
            for (int i = 0; i < ratings.length; i++) {
                if (ratings[i] > 0) {  // 只考虑评分过的图书
                    bookAverageRatings.merge(i + 1, ratings[i], Double::sum);  // 累加评分
                }
            }
        }

        // 计算每本图书的平均评分
        for (Map.Entry<Integer, Double> entry : bookAverageRatings.entrySet()) {
            entry.setValue(entry.getValue() / cluster.getPoints().size());
        }

        // 将图书的平均评分按从高到低排序
        List<BookRanking> bookRankings = new ArrayList<>();
        for (Map.Entry<Integer, Double> entry : bookAverageRatings.entrySet()) {
            Book book = bookMapper.selectOne(new QueryWrapper<Book>().lambda().eq(Book::getBookId, entry.getKey()));
            BookRanking ranking = new BookRanking(entry.getKey(), entry.getValue(),book.getTitle());
            bookRankings.add(ranking);
        }

        // 按评分降序排序
        bookRankings.sort((r1, r2) -> Double.compare(r2.getRating(), r1.getRating()));

        return bookRankings;
    }
}
